<?php
/**
 * XPHP Framework
 *
 * LICENSE
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * @category	XPHP
 * @package		XPHP_Router
 * @author		XWEB Dev Team
 * @copyright	Copyright (c) 2010-2011 XWEB. (http://xweb.vn)
 * @license		http://xphp.xweb.vn/license.html     GNU GPL License
 * @version		$Id: Router.php 20109 2011-22-08 02:05:09 Mr.UBKey $
 */
/**
 *
 **
 * XPHP_String.
 *
 * @see XPHP_String
 */
require_once 'XPHP/String.php';
/**
 * XPHP_Array.
 *
 * @see XPHP_Array
 */
require_once 'XPHP/Array.php';
/**
 * XPHP_Rewrite.
 *
 * @see XPHP_Rewrite
 */
require_once 'XPHP/Rewrite.php';
/**
 * XPHP_Router.
 *
 * @category	XPHP
 * @package		XPHP_Array
 * @author		Mr.UBKey
 * @link		http://xphp.xweb.vn/user_guide/xphp_router.html
 */
class XPHP_Router
{
    /**
     * Mảng lưu trữ  request uri
     * @var array
     */
    protected $_requestUri;
    /**
     * Danh sách các area và đường dẫn đến area
     * @var array
     */
    protected $_areas;
    /**
     * Tên area
     * @var string
     */
    protected $_area;
    /**
     * Prefix của area
     * @var string
     */
    public $areaKey;
    /**
     * Tên controller
     * @var string
     */
    protected $_controller;
    /**
     * Prefix của controller
     * @var string
     */
    public $controllerKey;
    /**
     * Tên action
     * @var string
     */
    protected $_action;
    /**
     * Prefix của action
     * @var string
     */
    protected $actionKey;
    /**
     * Prefix của action post
     * @var string
     */
    public $actionPOSTKey;
    /**
     * Prefix của action get
     * @var string
     */
    public $actionGETKey;
    /**
     * Prefix của action ajax
     * @var string
     */
    public $actionAJAXKey;
    /**
     * Tên thư mục chứa area
     * @var string 
     */
    public $areaDir;
    /**
     * Tên thư mục chứa controller
     * @var string 
     */
    public $controllerDir;
    /**
     * Tên thư mục chứa ứng dụng
     * @var string 
     */
    public $applicationDir;
    /**
     * Tham số truyền vào từ QueryString
     * @var array 
     */
    protected $_args = array();
    /**
     * Cho phép sử dụng cấu hình từ file config
     */
    public $usingConfig;
    /**
     * Khởi tạo các giá trị cho Router
     */
    public function __construct ()
    {
        //Load cấu hình trong file config với node router
        require_once 'XPHP/Config.php';
        XPHP_Config::load($this, 'router');
        /*
		 * Khởi tạo các giá trị mặc định 
		 */
        if (! $this->usingConfig) {
            $this->areaKey = "";
            $this->actionKey = "Action";
            $this->actionAJAXKey = "Ajax";
            $this->actionPOSTKey = "Post";
            $this->actionGETKey = "Get";
            $this->controllerKey = "Controller";
        }
        if (! $this->applicationDir)
            $this->applicationDir = "Application";
        if (! $this->areaDir)
            $this->areaDir = "Areas";
        if (! $this->controllerDir)
            $this->controllerDir = "Controllers";
    }
    /**
     * Gán một thể hiện của Router
     * @param $router
     * @return XPHP_Router
     */
    public function setInstance ($router)
    {
        if (get_class($router) == "XPHP_Router")
            return $router;
        else 
            if (is_array($router)) {
                if (isset($router['action']))
                    $this->setAction($router['action']);
                if (isset($router['controller']))
                    $this->setController($router['controller']);
                if (isset($router['area']))
                    $this->setArea($router['area']);
                if (isset($router['args']))
                    $this->setArgs($router['args']);
                return $this;
            }
    }
    /**
     * Lấy ra toàn bộ areas có trong thư mục areas và đường dẫn
     * @param void
     * @return array $areaName => $areaPath
     */
    public function getAreas ()
    {
        require_once 'XPHP/Directory.php';
        $this->_areas = XPHP_Directory::getSubDirectories($this->areaDir);
        return $this->_areas;
    }
    /**
     * Kiểm tra, phân tích request uri lấy ra Area, Controller, Action, Param (Thông tin router)
     * @param void
     * @return array Trả về mảng lưu trữ thông tin của router
     */
    public function analysisRequestUri ()
    {
        //Lấy toàn bộ area và đường dẫn
        $this->getAreas();
        //Lấy ra request uri
        $params = $this->getRequestUri();
        //Tạo thể hiện lớp XPHP_Rewrite
        $rewrite = new XPHP_Rewrite($this);
        //Xử lý XPHP_Rewrite nếu chưa có các tham số controller, action
        if ($this->emptyRouter() && ! $rewrite->processing()) {
            foreach ($params as $param) {
                //Bỏ qua dấu ? của get method hay không ?
                $pos = stripos($param, "?");
                if ($pos) {
                    $param = substr($param, 0, $pos);
                }
                if ($this->isArea($param) && empty($this->_area)) {
                    $this->setArea(XPHP_String::secure($param)); //area
                    array_shift($params);
                    continue;
                }
                if ($this->isController($param) && empty($this->_controller)) {
                    $this->setController(XPHP_String::secure($param)); //controller
                    array_shift($params);
                    continue;
                }
                if ($this->isAction($param) && empty($this->_action)) {
                    $this->setAction(XPHP_String::secure($param)); //action
                    array_shift($params);
                    break;
                }
            }
            //Bỏ qua dấu ? của get method
            for ($i = 0; $i < count($params); $i ++) {
                $pos = stripos($params[$i], "?");
                if ($pos) {
                    $params[$i] = substr($params[$i], 0, $pos);
                }
            }
            //args
            $this->setArgs(XPHP_Array::secure($params), true);
            //Default controller and action
            if (empty($this->_controller))
                $this->setController("Index");
            if (empty($this->_action))
                $this->setAction("index");
        }
    }
    /**
     * Kiểm tra xem tham số truyền vào có phải area hay không ?
     * @param string Chuỗi cần kiểm tra
     * @return boolean
     */
    public function isArea ($part)
    {
        if (empty($this->_requestUri))
            $this->getRequestUri();
        return isset($this->_areas[$part]);
    }
    /**
     * Kiểm tra xem tham số truyền vào có phải controller hay không ?
     * @param string Chuỗi cần kiểm tra
     * @return boolean
     */
    public function isController ($part)
    {
        //Nếu có area
        if (! empty($this->_area))
            $cfile = $this->_areas[$this->_area] . DIRECTORY_SEPARATOR .
             $this->controllerDir . DIRECTORY_SEPARATOR . $this->_area . "_" .
             $part . $this->controllerKey . '.php';
             //Nếu không có area 
        else
            $cfile = $this->applicationDir . DIRECTORY_SEPARATOR .
             $this->controllerDir . DIRECTORY_SEPARATOR . $part .
             $this->controllerKey . '.php';
        return is_file($cfile);
    }
    /**
     * Kiểm tra xem tham số truyền vào có phải action hay không ?
     * @param string Chuỗi cần kiểm tra
     * @return boolean
     */
    public function isAction ($part)
    {
        //Nếu có area
        if (! empty($this->_area) && ! empty($this->_controller))
            $class = $this->_area . $this->areaKey . '_' . $this->_controller .
             $this->controllerKey;
        else 
            if (! empty($this->_controller))
                $class = $this->_controller . $this->controllerKey;
            else
                return false;
        $isAction = false;
        //Kiểm tra xem có một trong những thể hiện của action hay không ?
        if (method_exists($class, $part . $this->actionKey))
            $isAction = true;
        else 
            if (method_exists($class, $part . $this->actionAJAXKey))
                $isAction = true;
            else 
                if (method_exists($class, $part . $this->actionPOSTKey))
                    $isAction = true;
                else 
                    if (method_exists($class, $part . $this->actionGETKey))
                        $isAction = true;
        return $isAction;
    }
    /**
     * Lấy ra request uri lưu lại dưới dạng mảng
     * @param void
     * @return array
     */
    public function getRequestUri ()
    {
        require_once 'XPHP/Uri.php';
        $uri = new XPHP_Uri();
        $this->_requestUri = $uri->parseRequestUri();
        return $this->_requestUri;
    }
    /**
     * Lấy ra tên area
     */
    public function getArea ()
    {
        return $this->_area;
    }
    /**
     * Gán tên area
     * @param string $area
     * @return XPHP_Router
     */
    public function setArea ($area)
    {
        $this->_area = $area;
        return $this;
    }
    /**
     * Lấy ra controller
     */
    public function getController ()
    {
        return $this->_controller;
    }
    /**
     * Gán tên controller
     * @param string $controller
     * @return XPHP_Router
     */
    public function setController ($controller)
    {
        $this->_controller = $controller;
        return $this;
    }
    /**
     * Lấy ra tên action
     */
    public function getAction ()
    {
        return $this->_action;
    }
    /**
     * Gán tên action
     * @param string $action
     * @return XPHP_Router
     */
    public function setAction ($action)
    {
        $this->_action = $action;
        return $this;
    }
    /**
     * Lấy ra các tham sô truyền vào
     */
    public function getArgs ()
    {
        return $this->_args;
    }
    /**
     * Gán tham số args
     * @param string $args
     * @param bool $override có ghi đè hay không, mặc định là không ghi đè
     * @return XPHP_Router
     */
    public function setArgs ($args, $override = NULL)
    {
        //Nếu không ghi đè(Mặc định không ghi đè)
        if ($override === NULL || ! $override) {
            if (is_array($args))
                $result = array_merge((array) $this->_args, (array) $args);
            else
                $this->_args[] = $args;
        } else {
            if (is_array($args))
                $this->_args = $args;
            else
                $this->_args = array($args);
        }
    }
    /**
     * Lấy ra thư mục chứa các area
     * @return string
     */
    public function getAreaDir ()
    {
        return $this->areaDir;
    }
    /**
     * Lấy ra thư mục application
     * @return string
     */
    public function getApplicationDir ()
    {
        return $this->applicationDir;
    }
    /**
     * Lấy ra tên thư mục chứa các controller
     * @return string
     */
    public function getControllerDir ()
    {
        return $this->controllerDir;
    }
    /**
     * Lấy ra đường dẫn của một area
     * @param string $area Tên Area cần lấy đường dẫn
     * @return string
     */
    public function getAreaPaths ($area)
    {
        return $this->_areas[$area];
    }
    /**
     * Lấy ra danh sách các area và đường dẫn của nó
     * @return string
     */
    public function getListAreas ()
    {
        return $this->_areas;
    }
    /**
     * Lấy ra Controller Key
     * @return string
     */
    public function getControllerKey ()
    {
        return $this->controllerKey;
    }
    /**
     * Lấy ra Action Key
     * @return string
     */
    public function getActionKey ()
    {
        return $this->actionKey;
    }
    /**
     * Lấy ra Area Key
     * @return string
     */
    public function getAreaKey ()
    {
        return $this->areaKey;
    }
    /**
     * Lấy ra thể hiện của của Router
     * @return XPHP_Router
     */
    public function getInstant ()
    {
        return clone $this;
    }
    /**
     * Xóa toàn bộ các thông tin action, controller, area detect được
     * @return bool
     */
    public function emptyRouter ()
    {
        return $this->_action == "" && $this->_controller == "" &&
         $this->_area == "";
    }
}